home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 02 - Basic Game Graphics / Simple GWorld ƒ / Simple GWorld.c next >
Encoding:
C/C++ Source or Header  |  1995-03-30  |  11.2 KB  |  423 lines  |  [TEXT/MMCC]

  1. //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
  2. //
  3. //    Simple GWorld.c
  4. //
  5. //    Simple demonstration of offscreen to onscreen blit.
  6. //
  7. //    The application:
  8. //    
  9. //    o    opens window and shows it onscreen
  10. //    o    creates an offscreen GWorld same size as window
  11. //    o    renders a rather ugly image offscreen
  12. //    o    hangs out in a simple even loop...
  13. //    o    blits the offscreen to the onscreen on update events
  14. //    o    any key-press activity quits the app
  15. //    o    NOTE: you can drag the window around. If you have
  16. //        multiple monitors, try dragging the window so that
  17. //        only one column of content-area pixels touches
  18. //        another screen; observe that screen's color environment.
  19. //
  20. //
  21. //    Among the concepts illustrated are:
  22. //
  23. //    +    creation of simple offscreen GWorlds
  24. //    +    offscreen to onscreen CopyBits
  25. //    +    drawing offscreen and blitting appears faster
  26. //        than drawing straight to screen (change
  27. //        kDraw2ScreenHack to TRUE to update directly
  28. //        to the screen.)
  29. //    
  30. //    History:
  31. //
  32. //    950304 jb: Written
  33. //
  34. //\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
  35.  
  36.  
  37. //  __#Defines________________________________________________________________________
  38. #undef TRUE
  39. #define TRUE                    !0        //Apple defines TRUE == 1; let's define it as *all* bits on
  40. #define DEBUG                    TRUE
  41. #define kMainWindowResID        1000
  42. #define kAppColorTableResID        300        //rather ugly gray-orange palette
  43. #define kDraw2ScreenHack        FALSE    //if TRUE, update directly to screen; don't 
  44.                                         //blit from offscreen; if FALSE, do the
  45.                                         //nice, offscreen draw and blit do-se-do
  46.  
  47. //  __#Headers________________________________________________________________________
  48. #include "Utils.h"            //several nubile functions are available here
  49. #include <Palettes.h>
  50. #include <math.h>            //for transcendental functions
  51. #include <QDOffscreen.h>    //need this for GWorlds
  52.  
  53. //  __#Protos_________________________________________________________________________
  54. //  __ Macros_________________________________________________________________________
  55. //  __ Enums__________________________________________________________________________
  56. //  __ Typedefs_______________________________________________________________________
  57. //  __ Static Protos__________________________________________________________________
  58. static Boolean OpenMainWindow( void );
  59. static Boolean InitApp( void );
  60. static void QuitApp( void );
  61. static void EventLoop( void );
  62. static Boolean CreateSimpleGWorld( GWorldPtr *newOffscreen );
  63. static void RenderToOffWorld( void );
  64. static void DrawSwirls( void );
  65. static void UpdateScreen( void );
  66.  
  67. //  __ Extern Globals_________________________________________________________________
  68. OSErr                gErr;
  69. Str32                gAppName;
  70. WindowPtr            gMainWindow;
  71. CGrafPtr            gMainPort;
  72. GDHandle            gMainGDev;
  73. CTabHandle            gOurColorTable;
  74. PaletteHandle         gAppPalette;
  75. GWorldPtr            gOurGWorld;
  76.  
  77. //  __ Static Globals_________________________________________________________________
  78. //  __ Functions______________________________________________________________________
  79.  
  80.  
  81. //____ main __________________________________________________________________________
  82. //
  83. void main( void )
  84. {
  85.     if (InitApp())        //Initialize managers, allocate global structures, etc…
  86.     {
  87.         EventLoop();    //Handle events until user quits
  88.         
  89.         QuitApp();        //dispose and release everything
  90.     }
  91.     
  92. }//main
  93.  
  94.  
  95. //____ InitApp __________________________________________________________________________
  96. //
  97. //    Returns FALSE if there were any problems initializing
  98. //
  99. static Boolean InitApp( void )
  100. {
  101.     ToolBoxInit();
  102.     
  103.     if (!EnviroCheck())
  104.         return FALSE;
  105.  
  106.     GetAppName((char *)gAppName);
  107.     
  108.     if (!OpenMainWindow())
  109.         return FALSE;
  110.     
  111.     if (!CreateSimpleGWorld( &gOurGWorld ))
  112.         return FALSE;
  113.  
  114. #if kDraw2ScreenHack == FALSE
  115.     RenderToOffWorld();
  116. #endif
  117.  
  118.     return TRUE;
  119. }//InitApp
  120.  
  121.  
  122. //____ QuitApp __________________________________________________________________________
  123. //
  124. //    Dispose of and release anything and everything
  125. //
  126. static void QuitApp( void )
  127. {
  128.     if(NULL != gMainWindow)
  129.         DisposeWindow(gMainWindow);
  130.     if(NULL != gOurColorTable)
  131.         DisposeCTable(gOurColorTable);
  132.     if (NULL != gOurGWorld)
  133.         DisposeGWorld(gOurGWorld);
  134. }//QuitApp
  135.  
  136.  
  137. //____ OpenMainWindow __________________________________________________________________________
  138. //
  139. //    Open our window, install palette built from a resource CTable.
  140. //    provided by the System.
  141. //
  142. static Boolean OpenMainWindow( void )
  143. {
  144. CTabHandle        tempColorTable;
  145.  
  146.     // create and show the window
  147.     gMainWindow = GetNewCWindow( kMainWindowResID, ( Ptr )NULL, ( WindowPtr ) -1 );    
  148.     if (NULL == gMainWindow)
  149.         return FALSE;
  150.     ShowWindow( gMainWindow );
  151.     SetPort( gMainWindow );
  152.     SetWTitle( gMainWindow,gAppName );
  153.  
  154.     GetGWorld( &gMainPort, &gMainGDev );    //save this info for later convenience
  155.     
  156.     tempColorTable = GetCTable( kAppColorTableResID );
  157.     mAssert(NULL != tempColorTable);
  158.     if (NULL == tempColorTable)
  159.         return FALSE;
  160.  
  161.     gAppPalette = NewPalette( 256, tempColorTable, pmTolerant + pmExplicit, 0x0000 );
  162.     NSetPalette( gMainWindow, gAppPalette, pmFgUpdates );
  163.     
  164.     return TRUE;
  165. }//OpenMainWindow
  166.  
  167.  
  168. //____ EventLoop __________________________________________________________________________
  169. //
  170. //    Nifty function shows off some ways to do Palette Animation
  171. //
  172. //    Returns    void
  173. //
  174. static void EventLoop( void )
  175. {
  176. Boolean            done;
  177. EventRecord        theEvent;
  178. short            thePart;
  179. WindowPtr        whichWin;
  180. RgnHandle        theGrayRgn;
  181. Rect            grayRgnLimitRect;
  182.  
  183.     theGrayRgn = GetGrayRgn();        //get region of all active screens (minus menu bar)
  184.     grayRgnLimitRect = (**theGrayRgn).rgnBBox;
  185.     
  186.     done = FALSE;
  187.     while (!done)
  188.     {
  189.         if(WaitNextEvent(everyEvent, &theEvent, 0L, 0L))
  190.         {
  191.             switch (theEvent.what)
  192.             {
  193.                 case mouseDown:
  194.                     thePart = FindWindow( theEvent.where, &whichWin );
  195.                     if (whichWin == gMainWindow)
  196.                     {
  197.                         if ((inDrag == thePart) || (inContent == thePart))
  198.                         {
  199.                             DragWindow( gMainWindow, theEvent.where, &grayRgnLimitRect);
  200.                         }
  201.                     }
  202.                 break;//mouseDown
  203.                 
  204.                 case keyDown:
  205.                     done = TRUE;
  206.                 break;
  207.  
  208.                 case updateEvt:
  209.                     if ((WindowPtr) theEvent.message == gMainWindow)
  210.                     {
  211.                         BeginUpdate(gMainWindow);
  212.                         UpdateScreen();
  213.                         EndUpdate(gMainWindow);
  214.                     }
  215.                 break;
  216.             }//switch (theEvent.what)
  217.         }//if WaitNextEvent
  218.  
  219.     }//while
  220.  
  221. }//EventLoop
  222.  
  223.  
  224.  
  225. //____ CreateSimpleGWorld __________________________________________________________________________
  226. //
  227. //    Makes an offscreen GWorld using current port and device as a template.
  228. //    Returns TRUE if offscreen was created, FALSE if there was a problem
  229. //
  230. static Boolean CreateSimpleGWorld( GWorldPtr *newOffscreen )
  231. {
  232. #define kNoCTable                    NULL
  233. #define kDeepestIntersectingDepth    0
  234.  
  235. Boolean    returnMe = FALSE;
  236. CGrafPtr    curPort;
  237. GDHandle    curDevice;
  238. Rect        globalRect;
  239. GWorldFlags    ourGWFlags;
  240.  
  241.     GetGWorld(&curPort, &curDevice);
  242.  
  243.     *newOffscreen = NULL;        //just in case NewGWorld fails
  244.     
  245.     ourGWFlags = noNewDevice;    //ourGWFlags describe certain options to NewGWorld.
  246.                                 //noNewDevice tells NewGWorld not to make a new
  247.                                 //GDevice for this GWorld. Instead, it will use the
  248.                                 //depth and Color Table of our curDevice (if the depth
  249.                                 //parameter is zero, then the deepest device intersecting
  250.                                 //the passed rectangle is used.)
  251.  
  252.     //get rectangle defining current port's interior, translate it
  253.     //into global coordinates.
  254.     globalRect = curPort->portRect;
  255.     LocalToGlobal(&mTopLeft(globalRect));
  256.     LocalToGlobal(&mBotRight(globalRect));
  257.     
  258.     gErr = NewGWorld(    newOffscreen, kDeepestIntersectingDepth,
  259.                          &globalRect, kNoCTable, curDevice, ourGWFlags);
  260.     mAssert(gErr == noErr);
  261.     if (noErr != gErr)
  262.         goto Xit;
  263.         
  264.     returnMe = TRUE;
  265. Xit:
  266.     SetGWorld(curPort, curDevice);
  267.     return(returnMe);
  268. }//CreateSimpleGWorld
  269.  
  270.  
  271. //____ RenderToOffWorld __________________________________________________________________________
  272. //
  273. //    Does time-consuming draw to offscreen world
  274. //
  275. static void RenderToOffWorld( void )
  276. {
  277. PixMapHandle    offPix;    
  278.  
  279.     mAssert(NULL != gOurGWorld);
  280.     if (NULL == gOurGWorld)
  281.         goto Xit;
  282.  
  283.     SetGWorld(gMainPort, gMainGDev);        //point to our window
  284.     MoveTo(8, 24);
  285.     DrawString("\pRendering Offscreen");    //let user know what's going on
  286.  
  287.     offPix = GetGWorldPixMap(gOurGWorld);    //use GetGWorldPixMap to get PixMap of
  288.                                             //an offscreen GWorld; dereferencing
  289.                                             //the GWorld pointer for it is a no-no.
  290.     mAssert(NULL != offPix);
  291.     if (NULL == offPix)
  292.         goto Xit;
  293.     
  294.     if(LockPixels(offPix))                    //Lock pixels before drawing
  295.     {
  296.         SetGWorld( gOurGWorld, NULL );        //SetGWorld ignores GDevice handle if port
  297.                                             //passed is a GWorldPtr; it uses the
  298.                                             //GDevice the port is attached to
  299.         
  300.         DrawSwirls();                        //draw those whacky swirls…
  301.  
  302.         UnlockPixels(offPix);
  303.     }
  304. Xit:
  305.     SetGWorld(gMainPort, gMainGDev);        //point to our window
  306.     return;
  307. }//RenderToOffWorld
  308.  
  309.  
  310.  
  311.  
  312.  
  313. //____ DrawSwirls __________________________________________________________________________
  314. //
  315. //    Draws silly swirls. Doesn't care what port it's pointed at, so make sure you've already
  316. //    pointed it at a valid port.
  317. //
  318. static void DrawSwirls( void )
  319. {
  320. #define kDotFactor            4
  321. #define mHalfRect            (theRadius / kDotFactor)
  322. #define kNumSwirls            4
  323. #define kNumSteps            254
  324. #define    mThetaStepSize         (6.283 / kNumSteps)                //how far around our circle to go
  325. #define kRadiusStep            1
  326.  
  327. short        step;
  328. short        x, y, cenX, cenY;
  329. double        theta;
  330. Rect        aRect;
  331. short        theRadius;
  332. RGBColor    theRGB;
  333. short        swirlNumber;
  334.     
  335.     cenX = qd.thePort->portRect.right / 2;
  336.     cenY = qd.thePort->portRect.bottom / 2;
  337.  
  338.     RGBForeColor(&blackRGB);
  339.     RGBForeColor(&whiteRGB);
  340.     EraseRect(&qd.thePort->portRect);
  341.  
  342.     for (swirlNumber = 0; swirlNumber < kNumSwirls; swirlNumber++)
  343.     {
  344.         theRadius = 0;
  345.         
  346.         for (step = 1, theta = (1.57 * swirlNumber); step <= kNumSteps; step++)
  347.         {
  348.             theta += mThetaStepSize;
  349.             
  350.             x = cenX + theRadius * cos(theta);
  351.             y = cenY - theRadius * sin(theta);
  352.     
  353.             theRGB = (**gAppPalette).pmInfo[step].ciRGB;
  354.             RGBForeColor(&theRGB);
  355.  
  356.             if (kDotFactor < theRadius)
  357.                 SetRect(&aRect, x - mHalfRect, y - mHalfRect, x + mHalfRect, y + mHalfRect);
  358.             else
  359.                 SetRect(&aRect, x, y, x + 1, y + 1);
  360.  
  361.             PaintOval(&aRect);
  362.  
  363.             theRadius += kRadiusStep;
  364.  
  365.         }
  366.     }
  367.     
  368. }//DrawSwirls
  369.  
  370.  
  371. //____ UpdateScreen __________________________________________________________________________
  372. //
  373. //    Blits offscreen to onscreen.
  374. //
  375. static void UpdateScreen( void )
  376. {
  377. CGrafPtr            oldPort;
  378. GDHandle            oldGDev;
  379. PixMapHandle        offPix;
  380.  
  381.     GetGWorld(&oldPort, &oldGDev);
  382.     
  383.     SetGWorld(gMainPort, gMainGDev);        //point to our window
  384.     
  385. #if kDraw2ScreenHack == TRUE
  386.     DrawSwirls();
  387.     goto Xit;
  388. #endif
  389.  
  390.     if (NULL == gOurGWorld)
  391.     {
  392.         MoveTo(8, 40);
  393.         DrawString("\pNo Offworld to Blit");
  394.         goto Xit;
  395.     }
  396.  
  397.     offPix = GetGWorldPixMap(gOurGWorld);    //get base address of our offscreen's PixMap
  398.     mAssert(NULL != offPix);
  399.     if (NULL == offPix)
  400.         goto Xit;
  401.  
  402.     //Finally, blit offscreen to onscreen
  403.     if(LockPixels(offPix))                    //Lock pixels before drawing
  404.     {
  405.         RGBForeColor(&blackRGB);        //ALWAYS set fore and back colors
  406.         RGBBackColor(&whiteRGB);        //to black and white, unless you
  407.                                         //want to colorize the blit
  408.  
  409.         // ctSeed slam: Force the color table seeds to be identical for speed
  410.          ( *( ( *( offPix ) )->pmTable ) )->ctSeed = 
  411.                  ( *( ( *( ( *gMainGDev )->gdPMap ) )->pmTable ) )->ctSeed;
  412.     
  413.         CopyBits(    (BitMap *)*offPix, &((GrafPtr)gMainPort)->portBits,
  414.                     &gMainPort->portRect, &gMainPort->portRect,
  415.                     srcCopy,NULL);
  416.         UnlockPixels(offPix);
  417.     }
  418.     
  419. Xit:
  420.     SetGWorld(oldPort, oldGDev);
  421.     return;
  422. }//UpdateScreen
  423.